const express = require("express");
const path = require("path");
const https = require("https");
// const http = require("http");
const fs = require("fs");
const multer = require("multer");
const app = express();
const { MongoClient, ObjectId } = require("mongodb");

const options = {
  host: "159.75.22.82",
  port: "27017",
  db_name: "FeedQRCode",
};

const MongoClientConfig = {
  useUnifiedTopology: true,
  auth: {
    username: "hongbin",
    password: "Hongbin",
  },
};

const url = `mongodb://${options.host}:${options.port}/${options.db_name}`;

const client = new MongoClient(url, MongoClientConfig);

client.connect(async err => {
  if (err) console.log("数据库连接失败", err)
  else console.log("数据库连接成功👏")
});

const mongoClient = client.db();

const qrcodeCollection = 'qrcode';

async function insertOne(collection, data) {
  return await mongoClient.collection(collection).insertOne(data)
    .then((res) => res)
    .catch((err) => { console.log("insertOne fail:", err) });
}

const findData = async ({ collection, find = {}, project = {}, sort = {}, limit = 20, skip = 0 }) =>
  await mongoClient.collection(collection)
    .find(find).project(project).sort(sort).limit(limit).skip(skip).toArray();


const privateKey = fs.readFileSync("../../Nginx_SSL/2_hongbin.xyz.key", "utf8");
const certificate = fs.readFileSync(
  "../../Nginx_SSL/1_hongbin.xyz_bundle.crt",
  "utf8"
);
const credentials = { key: privateKey, cert: certificate };
const httpsServer = https.createServer(credentials, app);
// const httpsServer = http.createServer(app);

const port = process.env.PORT || 8002;

httpsServer.listen(port, () => {
  console.log(">---:" + port);
});
//文件保存目录
const dest = __dirname + "/public/images/";
const objMulter = multer({ dest });

app.use(objMulter.any());

app.all("*", function (req, res, next) {
  //设置允许跨域的域名，*代表允许任意域名跨域
  res.header("Access-Control-Allow-Origin", "*");
  //允许的header类型
  res.header("Access-Control-Allow-Headers", "content-type");
  //跨域允许的请求方式
  res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
  if (req.method.toLowerCase() == "options") res.status(200).send();
  //让options尝试请求快速结束
  else next();
});

const REQUEST = {
  CREATE_QRCODE: "/createQRCode",
  GET_QRCODE_INFO: "/getQRCodeInfo",
  GET_IMAGE: "/public/images/",
  UPLOAD_QRCODE: "/uploadQRCode",
  WC_CREATE_QRCODE: "/wc_createQRCode",
};

const newId = async () => {
  const {
    recordset: [{ newId }],
  } = await sql.query`select newid() as newId`;
  return newId;
};

// /public/images/filename.png
app.get(REQUEST.GET_IMAGE + "*", function (req, res) {
  res.sendFile(__dirname + req.url);
  console.log("Request for " + req.url + " received.");
});

app.post(REQUEST.UPLOAD_QRCODE, (req, res) => {
  const {
    files: [{ filename, originalname }],
  } = req;
  console.log(req.files);
  fs.rename(`${dest}${filename}`, `${dest}${originalname}`, async err => {
    if (err) {
      console.error("fs rename:", err);
      res.statusCode(500);
      res.end("文件保存失败");
    } else {
      const filePath = `${REQUEST.GET_IMAGE}${originalname}`;
      res.json(filePath);
    }
  });
});
//微信小程序端 没有File对象 上传 base64
app.post(REQUEST.WC_CREATE_QRCODE, (req, res) => {
  let str = ""; //接收传来的数据

  req.on("data", function (data) {
    str += data; //每次获取的数据放到str中，目前只是字符串
  });
  req.on("end", async () => {
    const { title, price, imagePath } = JSON.parse(str);
    const id = await newId();
    console.log("微信端发送请求:", id, title, price);

    // const Buffer = new Buffer(imagePath,'base64');
    const imageName = `${id}.png`;
    fs.writeFile(`${dest}${imageName}`, imagePath, "base64", async err => {
      if (err) {
        res.status(400).send("图片保存错误");
      } else {
        try {
          await sql.query`
            insert into qrcode(id,title,price,img)
            values(${id},${title},${price},${imageName})
          `;
          res.send(id);
        } catch (error) {
          console.error(error);
          console.log("数据库插入失败");
          res.status(500);
          res.end("数据库插入失败");
        }
      }
    });
  });
});

//上传信息 存入数据库 返回id
app.post(REQUEST.CREATE_QRCODE, async (req, res) => {
  const {
    body: { title, price },
    files: [{ path: filePath, originalname, filename }],
  } = req;
  console.log(title, price, originalname);
  //获取拓展名
  const { ext } = path.parse(originalname);

  //不改名是二进制文件 需加上拓展名
  fs.rename(`${filePath}`, `${filePath}${ext}`, async err => {
    if (err) {
      console.error("fs rename:", err);
      res.statusCode(500);
      res.end("文件保存失败");
    } else {
      //ing 保存文件名 限制在public/images下  获取时直接获取路径的文件不安全
      const result = await insertOne(qrcodeCollection, {
        title, price, img: filename + ext
      })
      if (result) {
        res.json(result.insertedId).end();
      } else {
        console.log("数据库插入失败");
        res.statusCode(500).json("数据库插入失败");
      }
    }
  });
});

//获取 已经上传的二维码相关信息
app.get(REQUEST.GET_QRCODE_INFO, async (req, res) => {
  const { id } = req.query;
  const result = await findData({
    collection: qrcodeCollection, find: {
      _id: ObjectId(id)
    }
  })
  if (result.length) {
    //找到信息
    console.log(result[0]);
    res.json(result[0]).end();
  } else {
    res.writeHead(500);
  }
});

app.use("/", (req, res, next) => {
  let pathName = req.url;
  console.log(pathName);
  // 提供一个 icon就不会发起/favicon.ico的请求了
  if (pathName == "/") {
    pathName = "/index.html";
  }

  const extName = path.extname(pathName);
  fs.readFile(`../client/build${pathName}`, function (err, data) {
    if (err) {
      console.error(err);
      res.status(400).json(err);
    } else {
      const ext = getExt(extName);
      res.writeHead(200, { "Content-Type": ext + "; charset=utf-8" });
      res.write(data);
    }
    res.end();
  });
});

const EXT = {
  ".html": "text/html",
  ".css": "text/css",
  ".js": "text/js",
  ".ico": "image/x-icon",
  ".png": "image/png",
};
// 获取后缀名
getExt = extName => {
  return EXT[extName];
};
